#ifndef LISTA_H
#define LISTA_H

#include <stdbool.h>
#include <stddef.h>

/* ******************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS
 * *****************************************************************/

/* La lista está planteada como una lista de punteros genéricos. */

typedef struct lista lista_t;

typedef struct lista_iter lista_iter_t;


/* ******************************************************************
 *                    PRIMITIVAS BÁSICAS DE LA LISTA
 * *****************************************************************/


// Crea una lista
// Post: devuelve una nueva lista vacía
lista_t *lista_crear();

// Devuelve verdadero o falso, según si la lista tiene o no elementos enlazados.
// Pre: la lista fue creada.
bool lista_esta_vacia(const lista_t *lista);

// Agrega un nuevo elemento a la lista. Devuelve falso en caso de error.
// Pre: la lista fue creada.
// Post: se agregó un nuevo elemento a la lista y se encuentra al principio.
bool lista_insertar_primero(lista_t *lista, void *dato);

// Agrega un nuevo elemento a la lista. Devuelve falso en caso de error.
// Pre: la lista fue creada.
// Post: se agregó un nuevo elemento a la lista y valor se encuentra al final.
bool lista_insertar_ultimo(lista_t *lista, void *dato);

// Devuelve el contenido del primer elemento de la lista y lo elimina.
// Si lista está vacía devuelve NULL.
// Pre: la lista fue creada.
// Post: se devolvió el contenido del primer elemento de la lista y se lo eliminó.
void *lista_borrar_primero(lista_t *lista);

// Obtiene el valor del primer elemento de la lista. Si la lista tiene
// elementos, se devuelve el valor del primero, si está vacía devuelve NULL.
// Pre: la lista fue creada.
// Post: se devolvió el primer elemento de la lista, cuando no está vacía.
void *lista_ver_primero(const lista_t *lista);

// Devuelve la cantidad de elementos que tiene la lista.
// Pre: la lista fue creada.
// Post: devuelve la canitdad de elementos que tiene la lista.
size_t lista_largo(const lista_t *lista);

// Destruye la lista. Si se recibe la función destruir_dato por parámetro,
// para cada uno de los elementos de la lista llama a destruir_dato.
// Pre: la lista fue creada, la función destruir_dato es una función capaz de destruir
// los datos de la lista, o NULL en caso de que no se la utilice.
// Post: se eliminaron todos los elementos de la listas.
void lista_destruir(lista_t *lista, void destruir_dato(void *));

/* ******************************************************************
 *                    PRIMITIVAS DE ITERACIÓN
 * *****************************************************************/

// Crea un iterador.
// Post: devuelve un nuevo iterador.
lista_iter_t *lista_iter_crear(const lista_t *lista);

// Pre: el iterador fue creado.
// Post: avanza un nodo en la iteracion.
bool lista_iter_avanzar(lista_iter_t *iter);

// Pre: el iterador fue creado.
// Post: muestra el contenido de la posicion del iterador.
void *lista_iter_ver_actual(const lista_iter_t *iter);

// Pre: el iterador fue creado.
// Post: devuelve verdadero si el iterador se encuentra apuntando al final de la lista.
bool lista_iter_al_final(const lista_iter_t *iter);

// Pre: el iterador fue creado.
// Post: destruye el iterador.
void lista_iter_destruir(lista_iter_t *iter);

/* ******************************************************************
 *                    PRIMITIVAS DE LISTAS JUNTO CON ITERADOR
 * *****************************************************************/

// Inserta un elemento en la lista en la posicion del iterador.
// Pre: la lista fue creada, el iterador fue creado.
// Post: devuelve verdadero si el dato se ingreso en la posicion del iterador
// y el iterador quedo apuntando a ese nuevo dato.
// Caso contrario devuelve falso.
bool lista_insertar(lista_t *lista, lista_iter_t *iter, void *dato);

// Elimina un elemento en la posicion del iterador.
// Pre: la lista fue creada, el iterador fue creado.
// Post: devuelve el dato apuntado por el elemento eliminado, NULL en otro caso.
void *lista_borrar(lista_t *lista, lista_iter_t *iter);

/* ******************************************************************
 *                    PRIMITIVAS DE ITERADOR INTERNO
 * *****************************************************************/

// Pre: la lista fue creada
// Post: a cada elemento de la lista se le aplica la funcion visitar.
// Opcionalmente se puede usar el parametro extra para mas opciones.
void lista_iterar(lista_t *lista, bool (*visitar)(void *dato, void *extra), void *extra);


#endif // LISTA_H
